package com.sneaker.shower.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Lists;
import com.sneaker.shower.common.BizException;
import com.sneaker.shower.entity.domain.order.SubOrderDO;
import com.sneaker.shower.entity.domain.order.discount.CouponDO;
import com.sneaker.shower.entity.domain.order.discount.CouponTransactionDO;
import com.sneaker.shower.entity.dto.coupon.CouponCreateDTO;
import com.sneaker.shower.entity.dto.coupon.CouponDTO;
import com.sneaker.shower.entity.dto.coupon.CouponRespDTO;
import com.sneaker.shower.entity.enums.CouponTypeEnums;
import com.sneaker.shower.mapper.CouponMapper;
import com.sneaker.shower.mapstruct.CouponMapStruct;
import com.sneaker.shower.service.CouponService;
import com.sneaker.shower.service.CouponTransactionService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author Hechangjian
 * @version 1.0
 * @className CouponServiceImpl
 * @date 2019/11/26 11:59
 * @description
 * @program bath
 */
@Service
@Slf4j
public class CouponServiceImpl extends ServiceImpl<CouponMapper, CouponDO> implements CouponService {

    private final CouponTransactionService transactionService;

    @Value("${coupon.password}")
    private String PASSWORD;

    @Value("${coupon.salt}")
    private String SALT;

    @Autowired
    public CouponServiceImpl(CouponTransactionService transactionService) {
        this.transactionService = transactionService;
    }

    public static void main(String[] args) {
        System.out.println(Md5Crypt.md5Crypt("qiuxiezaotang".getBytes()));
    }

    @Override
    public List<CouponDTO> createCoupon(CouponCreateDTO couponCreateDTO) {
        if (StringUtils.isEmpty(couponCreateDTO.getPassword())) {
            throw new BizException("密码不能为空");
        }
        if (!Objects.equals(PASSWORD, Md5Crypt.md5Crypt(couponCreateDTO.getPassword().getBytes(), SALT))) {
            throw new BizException("密码错误");
        }
        if (couponCreateDTO.getDiscountFee() == null ||
                couponCreateDTO.getDiscountFee().compareTo(BigDecimal.ZERO) <= 0) {
            throw new BizException("请输入正确的优惠金额");
        }
        List<CouponDO> doList = Lists.newArrayList();
        for (Integer i = 0; i < couponCreateDTO.getCount(); i++) {
            CouponDO couponDO = new CouponDO();
            couponDO.setGuid(IdWorker.getId());
            couponDO.setType(couponCreateDTO.getType());
            couponDO.setCouponNo(IdWorker.get32UUID().substring(0, 10).toUpperCase());
            couponDO.setDiscountFee(couponCreateDTO.getDiscountFee());
            couponDO.setIsEnable(true);
            couponDO.setIsUsed(false);
            couponDO.setExpiredTime(LocalDateTime.now().plusDays(couponCreateDTO.getExpiredDays().longValue()).toLocalDate().atTime(23, 59, 59, 0));
            doList.add(couponDO);
        }
        if (!this.saveBatch(doList)) {
            throw new BizException("优惠券生成失败 请稍后重试");
        }
        List<CouponRespDTO> couponRespDTOS = CouponMapStruct.INSTANCE.doList2DTOList(doList);

        return couponRespDTOS.stream().map(o -> (CouponDTO) o).collect(Collectors.toList());
    }

    @Override
    public String disableAll() {
        CouponDO couponDO = new CouponDO();
        couponDO.setIsEnable(false);
        return this.update(couponDO, new LambdaQueryWrapper<CouponDO>().eq(CouponDO::getIsUsed, false)) ? "停用成功" : "停用失败";
    }

    @Override
    public CouponDO checkCouponState(Long couponGuid, String couponNo) {
        CouponDO couponDO;
        if (couponGuid != null) {
            couponDO = getById(couponGuid);
        } else {
            couponDO = getOne(new LambdaQueryWrapper<CouponDO>().eq(CouponDO::getCouponNo, couponNo));
        }
        if (couponDO == null) {
            throw new BizException("优惠券不存在");
        }
        if (couponDO.getIsUsed()) {
            throw new BizException("优惠券已被使用");
        }
        if (!couponDO.getIsEnable()) {
            throw new BizException("优惠券已被禁用");
        }
        if (LocalDateTime.now().isAfter(couponDO.getExpiredTime())) {
            throw new BizException("优惠券已过期");
        }
        if (couponDO.getDiscountFee() == null) {
            throw new BizException("优惠券无效，无优惠金额");
        }
        if (CouponTypeEnums.FREE_COUPON.getCode() == couponDO.getType()) {
            List<CouponTransactionDO> userCouponTransaction = transactionService.getUserCouponTransaction(couponDO.getType());
            if (!CollectionUtils.isEmpty(userCouponTransaction)) {
                throw new BizException("每个用户只能使用一次免单券");
            }
        }
        return couponDO;
    }

    @Override
    public CouponRespDTO getCouponInfo(Long couponGuid, Long subOrderGuid) {
        return CouponMapStruct.INSTANCE.do2RespDTO(this.getById(couponGuid));
    }

    /**
     * @param subOrderDO
     * @param couponDO
     */
    @Override
    public void useCoupon(SubOrderDO subOrderDO, CouponDO couponDO) {
        // 添加优惠券使用流水
        CouponTransactionDO couponTransactionDO = new CouponTransactionDO();
        couponTransactionDO.setCouponGuid(couponDO.getGuid());
        couponTransactionDO.setCouponType(couponDO.getType());
        couponTransactionDO.setSubOrderGuid(subOrderDO.getGuid());
        couponTransactionDO.setUserGuid(subOrderDO.getUserGuid());
        BigDecimal discountFee = BigDecimal.ZERO;
        switch (subOrderDO.getOrderPrice().compareTo(couponDO.getDiscountFee())) {
            case 0:
            case -1:
                discountFee = subOrderDO.getOrderPrice();
                break;
            case 1:
                discountFee = couponDO.getDiscountFee();
                break;
        }
        couponTransactionDO.setDiscountFee(discountFee);
        couponTransactionDO.setGuid(IdWorker.getId());
        transactionService.createTransaction(couponTransactionDO);

        //使用优惠券
        couponDO.setIsUsed(true);
        this.updateById(couponDO);
    }
}
